用etcd做go-micro的服务发现
(给Go开发大全
加星标)
来源:池塘边的卡夫卡
https://zhuanlan.zhihu.com/p/79897640
【导读】做微服务架构,微服务的治理统一框架其实非常有必要。本文介绍了如何使用golang和etcd实现服务发现。
在golang的生态中有众多框架,比如go-micro和go-kit还有华为开源的ServiceComb。
go-micro提供了一系列的组件,隐藏了分布式系统的复杂性,并为开发人员提供了很好的理解概念。开发者在开发的时候选择自己的组件就好了,如果系统不能支持,可以很方便的扩展。
在使用go-micro的服务发现组件的时候,由于我个人非常喜欢etcd。并且在一些分布式系统中可能会使用到分布式锁,所以服务发现的驱动我首选etcd。go-micro为etcd提供两组api一组是etcd一组是etcdv3。抱着用新不用久的思想果断选择etcdv3,这时候发现其实有一些坑。
按照官方文档我们的驱动选择etcd。代码如下
registerDrive := etcdv3.NewRegistry(func(op *registry.Options) {
op.Addrs = []string{
"http://127.0.0.1:2379",
}
})
service := micro.NewService(
micro.Transport(tg.NewTransport()),
micro.Server(grpc.NewServer()),
micro.Registry(registerDrive),
micro.Broker(brokerDrive),
micro.Name("userSrv"),
micro.Version("latest"),
)
然后我们启动etcd,启动etcd这时候发现报错。
../../../../github.com/coreos/etcd/clientv3/auth.go:121:72: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"vendor/google.golang.org/grpc".CallOption in argument to auth.remote.AuthEnable
../../../../github.com/coreos/etcd/clientv3/auth.go:126:74: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"vendor/google.golang.org/grpc".CallOption in argument to auth.remote.AuthDisable
../../../../github.com/coreos/etcd/clientv3/auth.go:131:152: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserAdd
../../../../github.com/coreos/etcd/clientv3/auth.go:136:144: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserAdd
../../../../github.com/coreos/etcd/clientv3/auth.go:141:86: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserDelete
../../../../github.com/coreos/etcd/clientv3/auth.go:146:122: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserChangePassword
../../../../github.com/coreos/etcd/clientv3/auth.go:151:104: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserGrantRole
../../../../github.com/coreos/etcd/clientv3/auth.go:156:80: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserGet
../../../../github.com/coreos/etcd/clientv3/auth.go:161:72: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserList
../../../../github.com/coreos/etcd/clientv3/auth.go:166:106: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserRevokeRole
../../../../github.com/coreos/etcd/clientv3/auth.go:166:106: too many errors
这时候我们谷歌一下,查查到底为啥报错。发现在etcd的github里面有一条issues。https://link.zhihu.com/?target=https%3A//github.com/etcd-io/etcd/issues/10051
这时候我们就清楚什么原因了,在go-micro里面引用的etcd的包是 github.com/coreos/etcd/而不是go.etcd.io/etcd/clientv这样一来可能就需要改源码了。
找到包github.com/micro/go-plu下发现三个文件一个个改掉就好
//watcher.go
import (
"context"
"errors"
"time"
//"github.com/coreos/etcd/clientv3"
"go.etcd.io/etcd/clientv3"
"github.com/micro/go-micro/registry"
)
//etcdv3.go
import (
"context"
"crypto/tls"
"encoding/json"
"errors"
"path"
"strings"
"sync"
"time"
//"github.com/coreos/etcd/clientv3"
"go.etcd.io/etcd/clientv3" // 新加
"github.com/micro/go-micro/config/cmd"
"github.com/micro/go-micro/registry"
//"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
"go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" // 新加
hash "github.com/mitchellh/hashstructure"
)
改掉这些代码的时候发现etcd存进去的时候前缀我们顺便再机器上面watch一下
var (
prefix = "/micro-registry"
)
etcdctl watch "/micro-registry" --prefix
运行代码 看看我们watch监控的结果
PUT
/micro-registry/userSrv/userSrv-4dfc1310-ba3e-4f76-a770-74ae5b4c074e
{"name":"userSrv","version":"latest","metadata":null,"endpoints":[{"name":"User.Call","request":{"name":"Request","type":"Request","values":[{"name":"name","type":"string","values":null}]},"response":{"name":"Response","type":"Response","values":[{"name":"msg","type":"string","values":null}]},"metadata":{"stream":"false"}},{"name":"User.PingPong","request":{"name":"Context","type":"Context","values":null},"response":{"name":"Stream","type":"Stream","values":null},"metadata":{"stream":"true"}},{"name":"User.Stream","request":{"name":"Context","type":"Context","values":null},"response":{"name":"Stream","type":"Stream","values":null},"metadata":{"stream":"true"}}],"nodes":[{"id":"userSrv-4dfc1310-ba3e-4f76-a770-74ae5b4c074e","address":"10.0.2.15:38068","metadata":{"broker":"rabbitmq","registry":"etcdv3","server":"grpc","transport":"grpc"}}]}
停止程序
DELETE
/micro-registry/userSrv/userSrv-4dfc1310-ba3e-4f76-a770-74ae5b4c074e
这样一来我们就可以使用etcd做服务发现了,其实关于这一块的代码也很简单,甚至你自己也可以去实现。具体可以参照他的代码,有空甚至你可以使用redis的发布订阅或者写一个基于redis驱动的练练手。
// 需要实现的接口如下
type Registry interface {
Register(*Service, ...RegisterOption) error
Deregister(*Service) error
GetService(string) ([]*Service, error)
ListServices() ([]*Service, error)
Watch(...WatchOption) (Watcher, error)
String() string
Options() Options
}
另外需要删除etcd包下面的vendor文件,不然也会报错。
其他
上述的容器都不是goroutines 安全的
上面的lr 也不是goroutines 安全的
Ring 中不建议在Do 方法中修改Ring 的指针,行为是未定义的
- EOF -
如果觉得本文不错,欢迎转发推荐给更多人。
分享、点赞和在看
支持我们分享更多好文章,谢谢!